/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin			*/
/*	Project:	GlbKv-1.0.0			*/
/*	Author:		gonsg_libin			*/
/*	Date:		2013_09_18			*/
/*	File:		GlbKv.cpp			*/
/********************************************************/

#include "GlbKv.h"

static GlbNet::CGlbUdp sg_CUdp;
static GlbNet::CGlbMulti sg_CMulti;
static GlbIpc::CGlbThash sg_CThash;
static UINT sg_uiField = GLB_KV_FIELD;
static UINT sg_uiSleep = GLB_KV_SLEEP;
static UINT sg_uiGlobal = GLB_KV_GLOBAL;
static UINT sg_uiTimeout = GLB_KV_TIMEOUT;
static ULONG sg_ulBucket = GLB_KV_BUCKET;

int main(int argc, char* argv[])
{
	int iPool = 1;
	int iCount = 0;
 	int iIndex = 0;
	int iReturn = 0;
	CGlbThread CAdmin;
	CGlbThread* pCMulti = NULL;
	CGlbThread* pCAccept = NULL;
	char szMulti[GLB_URL] = GLB_KV_MULTI;
	char szListen[GLB_URL] = GLB_KV_LISTEN;

	struct option stOptions[] = {
		{"pool", 1, 0, 'p'},
		{"field", 1, 0, 'f'},
		{"multi", 1, 0, 'm'},
		{"sleep", 1, 0, 's'},
		{"global", 1, 0, 'g'},
		{"listen", 1, 0, 'l'},
		{"bucket", 1, 0, 'b'},
		{"timeout", 1, 0, 't'},
		{"version", 0, 0, 'v'},
		{"help", 0, 0, 'h'},
		{0, 0, 0, 0},
	};

	while (true) {
		iReturn = getopt_long(argc, argv, "p:f:m:s:g:l:b:t:vh", stOptions, &iIndex);
		if (iReturn < 0) {
			break;
		}
		switch (iReturn) {
			case 'p':
				iPool = atoi(optarg);
				break;
			case 'm':
				strncpy(szMulti, optarg, GLB_URL);
				szMulti[strlen(optarg)] = '\0';
				break;
			case 'l':
				strncpy(szListen, optarg, GLB_URL);
				szListen[strlen(optarg)] = '\0';
				break;
			case 'f':
				sg_uiField = atoi(optarg);
				break;
			case 's':
				sg_uiSleep = atoi(optarg);
				break;
			case 'g':
				sg_uiGlobal = atoi(optarg);
				break;
			case 'b':
				sg_ulBucket = atol(optarg);
				break;
			case 't':
				sg_uiTimeout = atoi(optarg);
				break;
			case 'v':
				GLB_PRINT("Copyright (C) 2012 Gong Li Bin\n");
				GLB_PRINT("%s Build on %s %s.\n", GLB_KV_VERSION, __DATE__, __TIME__);
				return GLB_SUCCESS;
			case 'h':
				GlbKvHelp(argv[0]);
				return GLB_SUCCESS;
			default:
				return GLB_SUCCESS;
		}
	}

	GLB_INFO("Pool: %d\n", iPool);
	GLB_INFO("Multi: %s\n", szMulti);
	GLB_INFO("Listen: %s\n", szListen);
	GLB_INFO("Field: %d\n", sg_uiField);
	GLB_INFO("Sleep: %d\n", sg_uiSleep);
	GLB_INFO("Global: %d\n", sg_uiGlobal);
	GLB_INFO("Bucket: %ld\n", sg_ulBucket);
	GLB_INFO("Timeout: %d\n", sg_uiTimeout);

	signal(SIGINT, GlbKvQuit);
	signal(SIGSEGV, GlbKvQuit);
	signal(SIGTERM, GlbKvQuit);

	/* fork */
	#ifdef _GLB_DEBUG_
		iPool = 1;
	#else
		GlbFork();
	#endif

	/* thash */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Create Thash\n");
	#endif
	GlbIpcShmKernel(GLB_KV_SHM, GLB_KV_SHM);
	if (GLB_SUCCESS != sg_CThash.GlbThashCreate(GLB_IPC_PRIVATE, sg_ulBucket)) {
		GLB_ERROR("Failed to GlbThashCreate\n");
		return GLB_FAILURE;
	}

	/* admin */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Create admin thread\n");
	#endif
	CAdmin.GlbThreadRoutineSet(GlbKvAdmin);
	if (GLB_SUCCESS != CAdmin.GlbThreadCreate(NULL)) {
		return GLB_FAILURE;
	}

	/* multi */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("GlbKvMulti will listen ...\n");
	#endif
	if (GLB_SUCCESS == sg_CMulti.GlbNetInitRecv(szMulti)) {
		pCMulti = new CGlbThread[iPool];
		for (iCount = 0; iCount < iPool; iCount ++) {
			(pCMulti + iCount)->GlbThreadAttrInit();
			(pCMulti + iCount)->GlbThreadAttrSetDetach();
			(pCMulti + iCount)->GlbThreadRoutineSet(GlbKvMulti);
			(pCMulti + iCount)->GlbThreadCreate(NULL);
		}
		sg_CMulti.GlbNetClose();
	}
	else {
		GLB_ERROR("Failed to GlbNetInitRecv\n");
		return GLB_FAILURE;
	}

	/* accept */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("GlbKvAccept will listen ...\n");
	#endif
	if (GLB_SUCCESS == sg_CUdp.GlbNetInitRecv(NULL, szListen)) {
		pCAccept = new CGlbThread[iPool];
		for (iCount = 0; iCount < iPool; iCount ++) {
			(pCAccept + iCount)->GlbThreadAttrInit();
			(pCAccept + iCount)->GlbThreadRoutineSet(GlbKvAccept);
			(pCAccept + iCount)->GlbThreadCreate(NULL);
		}
		for (iCount = 0; iCount < iPool; iCount ++) {
			(pCAccept + iCount)->GlbThreadJoin(NULL);
		}
		sg_CUdp.GlbNetClose();
	}
	else {
		GLB_ERROR("Failed to GlbNetInitRecv\n");
	}

	return GLB_SUCCESS;
}

void GlbKvHelp(char* pszProc)
{
	GLB_PRINT("Usage: %s [options]\n", pszProc);
	GLB_PRINT("Valid options are:\n");
	GLB_PRINT("[0] -p or --pool:       set pool.\n");
	GLB_PRINT("[0] -f or --field:      set field.\n");
	GLB_PRINT("[0] -m or --multi:      set multi.\n");
	GLB_PRINT("[0] -s or --sleep:      set sleep.\n");
	GLB_PRINT("[0] -g or --global:     set global.\n");
	GLB_PRINT("[0] -l or --listen:     set listen.\n");
	GLB_PRINT("[0] -b or --bucket:     set bucket.\n");
	GLB_PRINT("[0] -t or --timeout:    set timeout.\n");
	GLB_PRINT("[0] -v or --version:    show version.\n");
	GLB_PRINT("[0] -h or --help:       show help.\n");
	GLB_PRINT("Copyright (C) 2012 Gong Li Bin\n");
	GLB_PRINT("%s Build on %s %s.\n", GLB_KV_VERSION, __DATE__, __TIME__);

	return;
}

void GlbKvQuit(int iSignal)
{
	GLB_ERROR("Stopped by signal %d\n", iSignal);
	sg_CThash.GlbThashDelete();

	exit(GLB_FAILURE);
}

void* GlbKvAdmin(void* pNULL)
{
	CGlbSet CSet;
	CGlbSet CBak;
	CGlbFile CFile;
	DIR* pDir = NULL;
	ULONG ulCount = 0;
	ULONG ulIndex = 0;
	ULONG ulTotal = 0;
	time_t ulTime = 0;
	GLBKVDATA_S* pstData = NULL;
	struct dirent* pstDir = NULL;
	char szFile[GLB_BYTE512] = { 0 };
	UCHAR uszPacket[GLB_KBYTES8] = { 0 };
	CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>::GLB_ITE iteCur;
	CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>** ppCTmap = NULL;

	while (true) {
		sleep(sg_uiSleep);

		/* backup */
		if (GLB_SUCCESS == chdir(GLB_KV_PATH)) {
			if (NULL != (pDir = opendir("."))) {
				if (GLB_SUCCESS == CBak.GlbSetInit(GLB_KV_TTL, GLB_BYTE128)) {
					while (NULL != (pstDir = readdir(pDir))) {
						if (GLB_SUCCESS == strncmp(pstDir->d_name, GLB_KV_FILE, strlen(GLB_KV_FILE))) {
							CBak.GlbSetIndexPut(CBak.GlbSetGetCount(), pstDir->d_name);
						}
					}
					CBak.GlbSetCompare(GlbKvCompare);
					CBak.GlbSetSort();

					if (CBak.GlbSetGetCount() > GLB_KV_BAK) {
						unlink((char*)CBak.GlbSetIndexGet(0));
					}

					CBak.GlbSetDestroy();
				}
				closedir(pDir);
			}
			else {
				GLB_ERROR("%s\n", strerror(errno));
			}
		}
		else {
			GLB_ERROR("%s\n", strerror(errno));
		}

		/* timeout */
		sprintf(szFile, "%s%s", GLB_KV_PATH, GLB_KV_FILE);
		GlbLocalDayTime(szFile + strlen(GLB_KV_PATH) + strlen(GLB_KV_FILE));
		if (GLB_SUCCESS == CFile.GlbFileOpen(szFile, GLB_O_CREATE | GLB_O_WRONLY)) {
			memcpy(uszPacket, &sg_uiTimeout, GLB_KV_TIM);
			CFile.GlbFileWrite(uszPacket, GLB_KV_TIM, false);
			for (ulCount = 0; ulCount < sg_ulBucket; ulCount ++) {
				ppCTmap = (CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>**)sg_CThash.GlbHashGetBucket(ulCount);
				if (NULL != *ppCTmap && (ulTotal = (*ppCTmap)->GlbMapSize()) > 0) {
					if (GLB_SUCCESS == CSet.GlbSetInit(ulTotal, sizeof(ULONGLONG))) {
						/* check */
						ulIndex = 0;
						ulTime = time(NULL);
						for (iteCur = (*ppCTmap)->GlbMapBegin(); iteCur != (*ppCTmap)->GlbMapEnd(); iteCur ++) {
							pstData = (GLBKVDATA_S*)&iteCur->second;
							if (static_cast<UINT>(ulTime - pstData->m_ulStamp) < sg_uiTimeout) {
								/* m_iLength + ullKey + ulTime + m_puszData */
								memset(uszPacket, '\0', GLB_KBYTES8);
								memcpy(uszPacket, &pstData->m_iLength, GLB_KV_INT);
								memcpy(uszPacket + GLB_KV_INT, &iteCur->first, GLB_KV_ULL);
								memcpy(uszPacket + GLB_KV_INT + GLB_KV_ULL, &pstData->m_ulStamp, GLB_KV_TIM);
								memcpy(uszPacket + GLB_KV_OFF, pstData->m_puszData, pstData->m_iLength);
								CFile.GlbFileWrite(uszPacket, GLB_KV_OFF + pstData->m_iLength, false);
							}
							else {
								CSet.GlbSetIndexPut(ulIndex ++, (void*)&iteCur->first);
								GlbFree((void**)&pstData->m_puszData);
							}
						}
	
						/* clear */
						for (ulIndex = 0; ulIndex < CSet.GlbSetGetCount(); ulIndex ++) {
							(*ppCTmap)->GlbTmapDelete(*(ULONGLONG*)CSet.GlbSetIndexGet(ulIndex));
						}

						CSet.GlbSetDestroy();
					}
					else {
						GLB_ERROR("%s\n", strerror(errno));
					}
				}
			}
			CFile.GlbFileClose();
		}
		else {
			GLB_ERROR("Failed to GlbFileOpen\n");
		}
	}

	pthread_exit(NULL);
}

void* GlbKvMulti(void* pNULL)
{
	bool bIns = true;
	UINT uiField = 0;
	ULONGLONG ullKey = 0;
	GlbNet::CGlbPro CPro;
	UCHAR uszPacket[GLB_KBYTES8] = { 0 };
	GlbNet::GLBPROKV_S stKv[GLB_KV_PAIR] = {{'\0', 0x00, NULL}};

	while (sg_CMulti.GlbNetRecv(uszPacket, GLB_KBYTES8) > 0) {
		#ifdef _GLB_DEBUG_
			GLB_PRINT("\n");
			GLB_DEBUG("Request:\n");
		#endif
		if (GLB_DEF_SUCC == GlbKvParse(uszPacket, &CPro, stKv)) {
			if ((ullKey = GlbKvGetKey(&stKv[GLB_KV_KEY - 1])) > 0) {
				if (sg_uiField > 0) {
					if (sg_uiField != (uiField = ullKey % sg_uiGlobal + 1)) {
						#ifdef _GLB_DEBUG_
							GLB_DEBUG("Field = %d, Will ignore\n", uiField);
						#endif
						bIns = false;
					}
				}
				if (true == bIns) {
					#ifdef _GLB_DEBUG_
						GLB_DEBUG("Field = %d, Will operate\n", uiField);
					#endif
					switch (CPro.GlbProGetVerb()) {
						case GLB_DEF_INST:
							if (GLB_DEF_SUCC != GlbKvInsert(ullKey, &stKv[GLB_KV_VAL - 1])) {
								GLB_ERROR("Failed to GlbKvInsert\n");
							}
							break;
						case GLB_DEF_DELT:
							GlbKvDelete(ullKey);
							break;
						default:
							break;
					}
				}
			}
			else {
				GLB_ERROR("Failed to GlbKvGetKey\n");
			}
		}
		else {
			GLB_ERROR("Failed to GlbKvParse\n");
		}
		memset(stKv, '\0', sizeof(GlbNet::GLBPROKV_S) * GLB_KV_PAIR);
		memset(uszPacket, '\0', GLB_KBYTES8);
		CPro.GlbProReset();
		bIns = true;
	}

	pthread_exit(NULL);
}

void* GlbKvAccept(void* pNULL)
{
	GlbNet::CGlbPro CPro;
	GlbNet::CGlbUdp CUdp;
	ULONGLONG ullKey = 0;
	UCHAR ucResult = GLB_DEF_SUCC;
	UCHAR uszSend[GLB_KBYTES8] = { 0 };
	UCHAR uszRecv[GLB_KBYTES8] = { 0 };
	GlbNet::GLBPROKV_S stKv[GLB_KV_PAIR] = {{'\0', 0x00, NULL}};

	CUdp.GlbNetSetSocket(sg_CUdp.GlbNetGetSocket());
	while (CUdp.GlbNetRecv(uszRecv, GLB_KBYTES8) > 0) {
		#ifdef _GLB_DEBUG_
			GLB_PRINT("\n");
			GLB_DEBUG("Request:\n");
		#endif
		/* parse */
		if (GLB_DEF_SUCC == (ucResult = GlbKvParse(uszRecv, &CPro, stKv))) {
			if ((ullKey = GlbKvGetKey(&stKv[GLB_KV_KEY - 1])) > 0) {
				switch (CPro.GlbProGetVerb()) {
					case GLB_DEF_INST:
						#ifdef _GLB_DEBUG_
							GLB_DEBUG("Insert -> Bucket: %lld\n", ullKey % sg_ulBucket);
						#endif
						ucResult = GlbKvInsert(ullKey, &stKv[GLB_KV_VAL - 1]);
						break;
					case GLB_DEF_SELT:
						#ifdef _GLB_DEBUG_
							GLB_DEBUG("Select -> Bucket: %lld\n", ullKey % sg_ulBucket);
						#endif
						ucResult = GlbKvSelect(ullKey, &stKv[GLB_KV_VAL - 1]);
						break;
					case GLB_DEF_DELT:
						#ifdef _GLB_DEBUG_
							GLB_DEBUG("Delete -> Bucket: %lld\n", ullKey % sg_ulBucket);
						#endif
						GlbKvDelete(ullKey);
						break;
					default:
						break;
				}
			}
			else {
				GLB_ERROR("Failed to GlbKvGetKey\n");
				ucResult = GLB_DEF_KYER;
			}
		}
		else {
			GLB_ERROR("Failed to GlbKvParse\n");
		}

		/* resp */
		CPro.GlbProPutBody(NULL);
		CPro.GlbProPutResult(ucResult);
		if (GLB_DEF_SELT == CPro.GlbProGetVerb()) {
			if (GLB_DEF_SUCC == ucResult) {
				CPro.GlbProPutTotal(GLB_KV_PAIR);
				CPro.GlbProPutLength(GlbProKvOutput(stKv, GLB_KV_PAIR, &uszSend[GLB_PRO_HEAD], GLB_KBYTES8));
			}
			else {
				CPro.GlbProPutTotal(GLB_PRO_0);
				CPro.GlbProPutLength(GLB_PRO_0);
			}
		}
		else {
			CPro.GlbProPutTotal(GLB_PRO_0);
			CPro.GlbProPutLength(GLB_PRO_0);
		}
		CPro.GlbProCreate(uszSend, GLB_PRO_HEAD);
		CUdp.GlbNetSend(uszSend, GLB_PRO_HEAD + CPro.GlbProGetLength());
		#ifdef _GLB_DEBUG_
			GLB_DEBUG("Response:\n");
			CPro.GlbProDisplay();
		#endif

		/* reset */
		memset(stKv, '\0', sizeof(GlbNet::GLBPROKV_S) * GLB_KV_PAIR);
		memset(uszSend, '\0', GLB_KBYTES8);
		memset(uszRecv, '\0', GLB_KBYTES8);
		ucResult = GLB_DEF_SUCC;
		CPro.GlbProReset();
	}

	pthread_exit(NULL);
}

UCHAR GlbKvInsert(ULONGLONG ullKey, GlbNet::GLBPROKV_S* pstVal)
{
	GLBKVDATA_S stData;
	UCHAR ucResult = GLB_DEF_SUCC;
	CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>** ppCTmap = NULL;

	#ifdef _GLB_DEBUG_
		CGlbTime CTime;
		CTime.GlbTimeOn();
	#endif

	/* key */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Key: %08llu\n", ullKey);
	#endif

	/* val */
	if (GLB_KV_VAL == pstVal->m_ucKey) {
		memset(&stData, '\0', sizeof(GLBKVDATA_S));
		if (NULL != (stData.m_puszData = (UCHAR*)GlbMalloc(sizeof(UCHAR) * pstVal->m_iLength))) {
			stData.m_ulStamp = time(NULL);
			stData.m_iLength = pstVal->m_iLength;
			memcpy(stData.m_puszData, pstVal->m_puszValue, pstVal->m_iLength);
			#ifdef _GLB_DEBUG_
				GLB_DEBUG("Val[%08d]: ********************\n", pstVal->m_iLength);
				GLB_DEBUG("Tim: %ld\n", stData.m_ulStamp);
			#endif
		}
		else {
			GLB_ERROR("Failed to GlbMalloc\n");
			ucResult = GLB_DEF_MALC;
		}
	}
	else {
		ucResult = GLB_DEF_KYER;
	}

	/* hash */
	if (GLB_DEF_SUCC == ucResult) {
		ppCTmap = (CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>**)sg_CThash.GlbHashGetBucket(ullKey);
		if (NULL == *ppCTmap) {
			sg_CThash.GlbThashLock();
			if (NULL == *ppCTmap) {
				*ppCTmap = new CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>;
				sg_CThash.GlbHashPutBucket(ullKey, (void**)ppCTmap);
				(*ppCTmap)->GlbTmapCreateLock();
				#ifdef _GLB_DEBUG_
					GLB_DEBUG("Create CGlbTmap, ");
				#endif
			}
			sg_CThash.GlbThashUnlock();
		}
		else {
			#ifdef _GLB_DEBUG_
				GLB_DEBUG("Attach CGlbTmap, ");
			#endif
		}

		if (true != ((*ppCTmap)->GlbTmapInsert(ullKey, stData))) {
			#ifdef _GLB_DEBUG_
				GLB_PRINT("GlbTmapInsert failure\n");
			#endif
			ucResult = GLB_DEF_INST;
		}
		else {
			#ifdef _GLB_DEBUG_
				GLB_PRINT("GlbTmapInsert success\n");
			#endif
		}
	}

	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Use time ");
		CTime.GlbTimeOff();
		CTime.GlbTimeDisplay();
	#endif

	return ucResult;
}

UCHAR GlbKvSelect(ULONGLONG ullKey, GlbNet::GLBPROKV_S* pstVal)
{
	GLBKVDATA_S stData;
	UCHAR ucResult = GLB_DEF_SUCC;
	CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>** ppCTmap = NULL;

	#ifdef _GLB_DEBUG_
		CGlbTime CTime;
		CTime.GlbTimeOn();
	#endif

	/* key */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Key: %08llu\n", ullKey);
	#endif

	/* val */
	ppCTmap = (CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>**)sg_CThash.GlbHashGetBucket(ullKey);
	if (NULL != *ppCTmap) {
		if (true == ((*ppCTmap)->GlbTmapSelect(ullKey, stData, sizeof(GLBKVDATA_S)))) {
			#ifdef _GLB_DEBUG_
				GLB_DEBUG("Val: %08d\n", stData.m_iLength);
				GLB_DEBUG("Tim: %ld\n", stData.m_ulStamp);
			#endif
			pstVal->m_ucKey = GLB_KV_VAL;
			pstVal->m_iLength = stData.m_iLength;
			pstVal->m_puszValue = stData.m_puszData;
		}
		else {
			#ifdef _GLB_DEBUG_
				GLB_DEBUG("Key NULL\n");
			#endif
			ucResult = GLB_DEF_NULL;
		}
	}
	else {
		#ifdef _GLB_DEBUG_
			GLB_DEBUG("CTmap NULL\n");
		#endif
		ucResult = GLB_DEF_NULL;
	}

	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Use time ");
		CTime.GlbTimeOff();
		CTime.GlbTimeDisplay();
	#endif

	return ucResult;
}

void GlbKvDelete(ULONGLONG ullKey)
{
	CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>** ppCTmap = NULL;

	#ifdef _GLB_DEBUG_
		CGlbTime CTime;
		CTime.GlbTimeOn();
	#endif

	/* key */
	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Key: %08llu\n", ullKey);
	#endif

	/* val */
	ppCTmap = (CGlbTmap<ULONGLONG, GLBKVDATA_S, GLBMAPDIGIT_O>**)sg_CThash.GlbHashGetBucket(ullKey);
	if (NULL != *ppCTmap) {
		(*ppCTmap)->GlbTmapDelete(ullKey);
	}
	else {
		#ifdef _GLB_DEBUG_
			GLB_PRINT("CTmap NULL\n");
		#endif
	}

	#ifdef _GLB_DEBUG_
		GLB_DEBUG("Use time ");
		CTime.GlbTimeOff();
		CTime.GlbTimeDisplay();
	#endif

	return;
}

UCHAR GlbKvParse(UCHAR* puszPacket, GlbNet::CGlbPro* pCPro, GlbNet::GLBPROKV_S* pstKv)
{
	UCHAR ucResult = GLB_DEF_SUCC;

	/* head */
	pCPro->GlbProParse(puszPacket, GLB_KBYTES8);
	#ifdef _GLB_DEBUG_
		pCPro->GlbProDisplay();
	#endif

	/* body */
	if (pCPro->GlbProGetLength() > 0) {
		if (pCPro->GlbProGetLength() < GLB_KBYTES8 - GLB_PRO_HEAD) {
			GlbProKvInput(pstKv, GLB_KV_PAIR, pCPro->GlbProGetBody(), pCPro->GlbProGetLength());
			#ifdef _GLB_DEBUG_
				GlbProKvDisplay(pstKv, GLB_KV_PAIR);
			#endif
			if (GLB_KV_KEY != pstKv->m_ucKey) {
				ucResult = GLB_DEF_KYER;
			}
		}
		else {
			ucResult = GLB_DEF_LENG;
		}
	}
	else {
		ucResult = GLB_DEF_LENG;
	}

	return ucResult;
}

ULONGLONG GlbKvGetKey(GlbNet::GLBPROKV_S* pstKey)
{
	char szKey[GLB_BYTE128] = { 0 };

	memcpy(szKey, pstKey->m_puszValue, pstKey->m_iLength);

	return strtoull(szKey, 0, 10);
}

int GlbKvCompare(const void* m, const void* n)
{
	return strcmp((char*)m, (char*)n);
}
